`timescale 1ns/100ps

`include "sim_glb.sv"

module tc;

localparam          CLK_PRD                 = 5;

reg                                         rst_n;
reg                                         clk;

localparam          WAVE_DW                 = 12;
localparam          WAVE_AM                 = 900;      // WAVE_AM < 2^(WAVE_DW-1)
localparam          NCO_DW                  = 16;
localparam          PHS_DW                  = 11;       // 3< PHS_DW <=NCO_DW

reg                 [NCO_DW-1:0]            freq_word;  // output frequency is F_clk*freq_word/(2^NCO_DW)
wire        signed  [WAVE_DW-1:0]           cos_dat;
wire        signed  [WAVE_DW-1:0]           sin_dat;

initial begin:CRG
    rst_n=1'b0;
    clk=1'b0;

    fork
        rst_n=#100.5 1'b1;
        forever clk=#CLK_PRD ~clk;
    join
end

RGRS_MNG    rgrs;
initial begin:REGRESS
    rgrs = new("tc_single_tone", 1);

    rgrs.wait_chks_done(100_000_000);
end

initial begin
//    freq_word = (1<<NCO_DW)/100;
    freq_word = 32;
end

cos_sin_wave #(
        .WAVE_DW                        (WAVE_DW                        ),
        .WAVE_AM                        (WAVE_AM                        ),	// WAVE_AM < 2^(WAVE_DW-1)
        .NEG_SIN                        (1'b0                           ),	// 1'b0:normal; 1'b1:invert sin;
        .NCO_DW                         (NCO_DW                         ),
        .PHS_DW                         (PHS_DW                         )	// 3< PHS_DW <=NCO_DW
) u_tone ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),
        .cke                            (1'b1                           ),

        .freq_word                      (freq_word                      ),	// output frequency is F_clk*freq_word/(2^NCO_DW)

        .cos_dat                        (cos_dat                        ),
        .sin_dat                        (sin_dat                        )
);

wire        signed  [WAVE_DW-1:0]           mix_i;
wire        signed  [WAVE_DW-1:0]           mix_q;

mixer #(
        .DW                             (WAVE_DW                        ),
        .CW                             (12                             ),
        .FREQ_DOWN                      (1'b0                           ),	// 1'b1:down(Fo=Fi-Fnco); 1'b0:up(Fo=Fi+Fnco)
        .PWR_LIMITED                    (1'b1                           ),	// set it to 1'b1 if power of din<=(2^(DW-1) -1)^2 for better timing
        .NCO_DW                         (NCO_DW                         ),
        .PHS_DW                         (PHS_DW                         )	// 3< PHS_DW <=NCO_DW
) u_mixer ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),
        .cke                            (1'b1                           ),

        .din_i                          (cos_dat                        ),
        .din_q                          (sin_dat                        ),

        .dout_i                         (mix_i                          ),
        .dout_q                         (mix_q                          ),

        .freq_word                      (16'd17                         )	// frequency of sin/cos is F_clk*freq_word/(2^NCO_DW)
);

cos_wave #(
        .WAVE_DW                        (WAVE_DW                        ),
        .WAVE_AM                        (WAVE_AM                        ),	// WAVE_AM < 2^(WAVE_DW-1)
        .NCO_DW                         (NCO_DW                         ),
        .PHS_DW                         (PHS_DW                         )	// 2< PHS_DW <=NCO_DW
) u_cos ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),
        .cke                            (1'b1                           ),

        .freq_word                      (freq_word                      ),	// output frequency is F_clk*freq_word/(2^NCO_DW)

        .cos_dat                        (                               )
);

localparam          CH_NUM                  = 4;
reg                 [NCO_DW-1:0]            cnt_acc;
wire                [NCO_DW-1:0]            cnt_tmp1;
wire                [NCO_DW-1:0]            cnt_tmp2;
wire                [NCO_DW-1:0]            cnt_tmp3;
wire                [CH_NUM*PHS_DW-1:0]     phase;      // (0:2*PI)
wire                [CH_NUM*WAVE_DW-1:0]    p4cos_dat;
wire                [CH_NUM*WAVE_DW-1:0]    p4sin_dat;
reg         signed  [WAVE_DW-1:0]           p4cos_dat_ary[CH_NUM-1:0];
reg         signed  [WAVE_DW-1:0]           p4sin_dat_ary[CH_NUM-1:0];

always@(posedge clk or negedge rst_n) begin
    if (rst_n==1'b0) begin
        cnt_acc <=`U_DLY {NCO_DW{1'b0}};
    end else begin
        cnt_acc <=`U_DLY cnt_acc + (freq_word<<2);
    end
end
assign cnt_tmp1 = cnt_acc + freq_word;
assign cnt_tmp2 = cnt_acc + (freq_word<<1);
assign cnt_tmp3 = cnt_acc + (freq_word<<1) + freq_word;
assign phase = {cnt_tmp3[NCO_DW-1-:PHS_DW],
                cnt_tmp2[NCO_DW-1-:PHS_DW],
                cnt_tmp1[NCO_DW-1-:PHS_DW],
                cnt_acc [NCO_DW-1-:PHS_DW]
               };
cos_sin_tab #(
        .WAVE_DW                        (WAVE_DW                        ),
        .WAVE_AM                        (WAVE_AM                        ),	// WAVE_AM < 2^(WAVE_DW-1)
        .NEG_SIN                        (1'b0                           ),	// 1'b0:normal; 1'b1:invert sin;
        .PHS_DW                         (PHS_DW                         ),
        .CH_NUM                         (CH_NUM                         )
) cos_sin_tab ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),
        .cke                            (1'b1                           ),

        .phase                          (phase                          ),	// (0:2*PI)
        .cos_dat                        (p4cos_dat                      ),	// [-WAVE_AM:WAVE_AM]
        .sin_dat                        (p4sin_dat                      )	// [-WAVE_AM:WAVE_AM]
);

always@(*) begin
    integer i;
    for(i=0; i<CH_NUM; i++) begin
        p4cos_dat_ary[i] = p4cos_dat[i*WAVE_DW+:WAVE_DW];
        p4sin_dat_ary[i] = p4sin_dat[i*WAVE_DW+:WAVE_DW];
    end
end

initial begin:GEN_
    integer         i;
    reg [7:0]       rand_dat;

    i   = 0;

    @(posedge rst_n);
    #500_000;

    rgrs.one_chk_done("sch num is done.");
end


endmodule

